/****************************************************
File Name:46-2-server.c
Author: Abby Cin
Mail: abbytsing@gmail.com
Created Time: Thu 11 Sep 2014 07:56:07 PM CST
*****************************************************/
// child process will inhert sigaction handler so
// child call dealing() will failed. In this case
// I ignored the error checking in dealing function
// I shall manual clean read target buffer by using line 52

#include"msg.h"
#include<fcntl.h>
#include<string.h>
#include<sys/wait.h>

void
dealing (int sig)
{
    int serrno;
    serrno = errno;
    if (sig == SIGCHLD)
    {
        while (waitpid (-1, NULL, WNOHANG) > 0)
          continue;
        errno = serrno;
    }
    else
    {
        int id;
        id = msgget (key, S_IWUSR | S_IRUSR | S_IWGRP);	// ignore error in child process
        msgctl (id, IPC_RMID, NULL);	// ignore error in child process
        signal (sig, SIG_DFL);	// disestablish handler
        raise (sig);		// raise signal again
    }
}

void
handler (const struct msgbuf *msg1)
{
    char *path;
    int fd;
    struct msgbuf tmp;

    if (strcpy (path, msg1->mtext) == NULL)
        err ("strcpy");
    if ((fd = open (path, O_RDONLY)) == -1)
        err ("open");

    tmp.mtype = 1;

    while (read (fd, tmp.mtext, DATA_SIZE) > 0)
    {
        if (msgsnd (msg1->id, (void *) &tmp, DATA_SIZE, 0) == -1)
            err ("msgsnd to client");
        memset (tmp.mtext, '\0', DATA_SIZE);
    }
    
    tmp.mtype = 3;
    if (msgsnd (msg1->id, (void *) &tmp, 0, 0) == -1)
        err ("send end signal");
    
    close (fd);
}

int
main (int argc, char *argv[])
{
    struct msgbuf msg1;
    int perm = S_IRUSR | S_IWUSR | S_IWGRP;
    int msgid;
    int status;
    pid_t pid;
    struct sigaction act;
    
    if (sigemptyset (&act.sa_mask) == -1)
        err ("sigemptyset");
    act.sa_flags = 0;
    act.sa_handler = dealing;
    
    if (sigaction (SIGINT, &act, NULL) == -1
      || sigaction (SIGCHLD, &act, NULL) == -1)
        err ("sigaction");
    
    msgid = (msgget (key, IPC_CREAT | IPC_EXCL | perm));
    if (msgid == -1 && errno != EEXIST)
        err ("msgget");
    
    msg1.mtype = 1;		// a test
    
    for (;;)
    {
        status = msgrcv (msgid, (void *) &msg1, DATA_SIZE, 0, 0);	// rcv msg from server msgq
        
        if (status == -1)
        {
            if (errno == EINTR)
              continue;
            else
              break;
        }
        pid = fork ();
        if (pid == -1)
            err ("fork");
        if (pid == 0)
        {
            handler (&msg1);
            _exit (0);
        }
    }
    if (msgctl (msgid, IPC_RMID, NULL) == -1 && errno != EINVAL)
        err ("remove server msgq");
    exit (0);
}

// kate: indent-mode cstyle; indent-width 2; replace-tabs on; 
